package model;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import model.Utils.FilesPlacer;

public class GenericTreeNode<T> {

	private T data;
	private List<GenericTreeNode<T>> children;
	private GenericTreeNode<T> parentNode;
	private Boolean isRoot;

	public GenericTreeNode(GenericTreeNode<T> parentNode) {
		super();
		children = new ArrayList<GenericTreeNode<T>>();
		
		this.parentNode = parentNode;
		if (parentNode == null) {
			isRoot = true;
		} else {
			isRoot = false;
		}
	}

	public GenericTreeNode(GenericTreeNode<T> parentNode, T data) {
		super();
		children = new ArrayList<GenericTreeNode<T>>();
		this.parentNode = parentNode;
		if (parentNode == null) {
			isRoot = true;
		} else {
			isRoot = false;
		}
		setData(data);
	}

	@SuppressWarnings("unchecked")
	public void prepareChildElementsForFileVO(float posX, float posY,
			float posZ, float objectScale) {

		FileVO file = (FileVO) this.getData();
		ArrayList<FileVO> childElements = new ArrayList<FileVO>();
		if (file.isDirectory()) {
			File children[] = file.listFiles();
			if (children != null) {
				for (File f : children) {
					childElements.add(new FileVO(f.getAbsolutePath(), file.getColorId()));
				}
			}
			if (childElements.size() > 0) {
				/*
				 * float r = ((float) (childElements.size() - 1) * objectScale)
				 * / (2 * (float) Math.PI); int objectsOnRadius = (int) (r /
				 * (objectScale)); // System.out.println(objectsOnRadius); for
				 * (int i = 0; i < childElements.size(); i++) { if (i <
				 * objectsOnRadius) { FileVO f = childElements.get(i);
				 * f.setPosX(posX + ((r * i) / objectsOnRadius));
				 * f.setPosY(posY); f.setPosZ(posZ); //
				 * System.out.println(f.getMimeType()); f.listPositions(); }
				 * else { FileVO f = childElements.get(i); f.setPosX((float)
				 * (posX + r Math.cos((i - objectsOnRadius) 2 Math.PI /
				 * (childElements.size() - objectsOnRadius))));
				 * f.setPosY((float) (posY + r Math.sin((i - objectsOnRadius) 2
				 * Math.PI / (childElements.size() - objectsOnRadius))));
				 * f.setPosZ(posZ); f.listPositions(); //
				 * System.out.println(f.getMimeType()); }
				 */

				FilesPlacer filesPlacer = new FilesPlacer();
				filesPlacer.placeFiles(childElements, posX, posY, posZ, true);
				for (FileVO child : childElements) {
					child.setRadius(filesPlacer.getRadius());				
				}
				
			}
			for (FileVO child : childElements) {
				this.addChild(new GenericTreeNode<T>(this, (T) child));
			}
		}

	}

	public List<GenericTreeNode<T>> getChildren() {
		return this.children;
	}

	public int getNumberOfChildren() {
		return getChildren().size();
	}

	public boolean hasChildren() {
		return (getNumberOfChildren() > 0);
	}

	public void setChildren(List<GenericTreeNode<T>> children) {
		this.children = children;
	}

	public void addChild(GenericTreeNode<T> child) {
		children.add(child);
	}

	public void addChildAt(int index, GenericTreeNode<T> child)
			throws IndexOutOfBoundsException {
		children.add(index, child);
	}

	public void removeChildren() {

		for (GenericTreeNode<T> node : this.children) {
			node.removeChildren();
			node.setParentNode(null);
		}
		this.children = new ArrayList<GenericTreeNode<T>>();
	}

	public void removeChildAt(int index) throws IndexOutOfBoundsException {
		children.remove(index);
	}

	public GenericTreeNode<T> getChildAt(int index)
			throws IndexOutOfBoundsException {
		return children.get(index);
	}

	public T getData() {
		return this.data;
	}

	public void setData(T data) {
		this.data = data;
	}

	public String toString() {
		return getData().toString();
	}

	public boolean equals(GenericTreeNode<T> node) {
		return node.getData().equals(getData());
	}

	public boolean hasParentElement() {
		if (parentNode != null) {
			return true;
		}
		return false;
	}

	public int hashCode() {
		return getData().hashCode();
	}

	public String toStringVerbose() {
		String stringRepresentation = getData().toString() + ":[";

		for (GenericTreeNode<T> node : getChildren()) {
			stringRepresentation += node.getData().toString() + ", ";
		}

		// Pattern.DOTALL causes ^ and $ to match. Otherwise it won't. It's
		// retarded.
		Pattern pattern = Pattern.compile(", $", Pattern.DOTALL);
		Matcher matcher = pattern.matcher(stringRepresentation);

		stringRepresentation = matcher.replaceFirst("");
		stringRepresentation += "]";

		return stringRepresentation;
	}

	public Boolean getIsRoot() {
		return isRoot;
	}

	public void setIsRoot(Boolean isRoot) {
		this.isRoot = isRoot;
	}

	public GenericTreeNode<T> getParentNode() {
		return parentNode;
	}

	public void setParentNode(GenericTreeNode<T> parentNode) {
		this.parentNode = parentNode;
	}
}
